def scalePcd(pcd, tag=None,suppress_print=True):
    """
    Ensure point cloud colors are in 0-255 range.
    If colors are in 0-1 range, scale them to 0-255.
    All color scaling should go through this function.
    
    Args:
        pcd: Point cloud array of shape (N, 6) [x, y, z, r, g, b] or RGB array of shape (N, 3) [r, g, b]
        tag: Optional tag for logging
    """
    if pcd is None or pcd.shape[0] == 0:
        return pcd
    
    # Handle different input formats
    if pcd.shape[1] == 6:  # Full point cloud [x, y, z, r, g, b]
        colors = pcd[:, 3:6]
        original_min = colors.min()
        original_max = colors.max()
        
        if original_max <= 1.1:  # If max value is <= 1.1, assume 0-1 range
            pcd = pcd.copy()
            pcd[:, 3:6] = colors * 255.0
            if not suppress_print:
                print(f"scalePcd.py: scalePcd({tag}) - {colors.min():.3f}-{colors.max():.3f} -> {pcd[:, 3:6].min():.3f}-{pcd[:, 3:6].max():.3f}")
        # else:
        #     print(f"scalePcd.py: scalePcd({tag}) - Colors range: {original_min:.3f} to {original_max:.3f}, already in 0-255 range, no scaling needed")
        
        return pcd
    
    elif pcd.shape[1] == 3:  # RGB only [r, g, b]
        colors = pcd
        original_min = colors.min()
        original_max = colors.max()
        
        if original_max <= 1.1:  # If max value is <= 1.1, assume 0-1 range
            pcd = pcd.copy()
            pcd = colors * 255.0
            if not suppress_print:
                print(f"scalePcd.py: scalePcd({tag}) - {colors.min():.3f}-{colors.max():.3f} -> {pcd.min():.3f}-{pcd.max():.3f}")
        # else:
        #     print(f"scalePcd.py: scalePcd({tag}) - RGB range: {original_min:.3f} to {original_max:.3f}, already in 0-255 range, no scaling needed")
        
        return pcd
    
    else:
        print(f"scalePcd.py: scalePcd({tag}) - Unsupported shape {pcd.shape}, expected (N, 6) or (N, 3)")
        return pcd

def scaleColors(colors, tag=None,suppress_print=True):
    """
    Scale only RGB colors to 0-255 range.
    Convenience function for when you only have RGB data.
    
    Args:
        colors: RGB array of shape (N, 3) [r, g, b] or (H, W, 3) for images
        tag: Optional tag for logging
    """
    if colors is None:
        return colors
    
    original_min = colors.min()
    original_max = colors.max()
    
    if original_max <= 1.1:  # If max value is <= 1.1, assume 0-1 range
        scaled_colors = colors * 255.0
        if not suppress_print:
            print(f"scalePcd.py: scaleColors({tag}) - {colors.min():.3f}-{colors.max():.3f} -> {scaled_colors.min():.3f}-{scaled_colors.max():.3f}")
        return scaled_colors
    else:
        # print(f"scalePcd.py: scaleColors({tag}) - Colors range: {original_min:.3f} to {original_max:.3f}, already in 0-255 range")
        return colors

def scaleDownColors(colors, tag=None,suppress_print=True):
    """
    For visualization: if colors max > 1.1, divide by 255 to get 0-1 range for display.
    Otherwise, return as is.
    """
    if colors is None:
        return colors
    original_min = colors.min()
    original_max = colors.max()
    if original_max > 1.1:
        scaled_colors = colors / 255.0
        if not suppress_print:
            print(f"scalePcd.py: scaleDownColors({tag}) - {colors.min():.3f}-{colors.max():.3f} -> {scaled_colors.min():.3f}-{scaled_colors.max():.3f}")
        return scaled_colors
    else:
        # print(f"scalePcd.py: scaleDownColors({tag}) - Colors already in 0-1 range: {original_min:.3f} to {original_max:.3f}")
        return colors

def scalePcdU(unified_data, ld_param, pipeMap,suppress_print=True):
    """
    Scale point cloud colors in unified_data for a specific ld_param.
    Only processes the pointcloud field corresponding to pipeMap[ld_param].
    
    Args:
        unified_data: Unified data dictionary containing pointcloud fields
        ld_param: Parameter from ld pipeline step (e.g., 'p', 's', 'r', 'v2', 'v3')
        pipeMap: Mapping from pipeline parameters to unified_data keys
    
    Returns:
        unified_data: Modified unified_data with scaled pointcloud colors
    """
    if ld_param not in pipeMap:
        print(f"scalePcd.py: scalePcdU - Invalid ld_param '{ld_param}', not found in pipeMap")
        return unified_data
    
    field_key = pipeMap[ld_param]
    
    # Only process pointcloud fields
    if 'pointcloud' not in field_key:
        print(f"scalePcd.py: scalePcdU - ld_param '{ld_param}' maps to '{field_key}', not a pointcloud field, skipping")
        return unified_data
    
    if field_key not in unified_data:
        print(f"scalePcd.py: scalePcdU - Field '{field_key}' not found in unified_data")
        return unified_data
    
    pointcloud_data = unified_data[field_key]
    if pointcloud_data is None:
        print(f"scalePcd.py: scalePcdU - Field '{field_key}' is None, skipping")
        return unified_data
    
    # Apply scaling to the specific pointcloud field
    scaled_pointcloud = scalePcd(pointcloud_data, tag=f"scalePcdU_{ld_param}_{field_key}")
    unified_data[field_key] = scaled_pointcloud
    
    if not suppress_print:
        print(f"scalePcd.py: scalePcdU - Scaled {field_key} for ld_param '{ld_param}'")
    return unified_data

def scalePcdD(pcd, tag=None,suppress_print=True):
    """
    Scale point cloud colors from 0-255 range back to 0-1 range.
    Used when saving pointcloud data to zarr storage.
    
    Args:
        pcd: Point cloud array of shape (N, 6) [x, y, z, r, g, b] or RGB array of shape (N, 3) [r, g, b]
        tag: Optional tag for logging
    
    Returns:
        pcd: Point cloud with colors scaled to 0-1 range
    """
    if pcd is None or pcd.shape[0] == 0:
        return pcd
    
    # Handle different input formats
    if pcd.shape[1] == 6:  # Full point cloud [x, y, z, r, g, b]
        colors = pcd[:, 3:6]
        original_min = colors.min()
        original_max = colors.max()
        
        if original_max > 1.1:  # If max value is > 1.1, assume 0-255 range
            pcd = pcd.copy()
            pcd[:, 3:6] = colors / 255.0
            if not suppress_print:
                print(f"scalePcd.py: scalePcdD({tag}) - {colors.min():.3f}-{colors.max():.3f} -> {pcd[:, 3:6].min():.3f}-{pcd[:, 3:6].max():.3f}")
        # else:
        #     print(f"scalePcd.py: scalePcdD({tag}) - Colors range: {original_min:.3f} to {original_max:.3f}, already in 0-1 range, no scaling needed")
        
        return pcd
    
    elif pcd.shape[1] == 3:  # RGB only [r, g, b]
        colors = pcd
        original_min = colors.min()
        original_max = colors.max()
        
        if original_max > 1.1:  # If max value is > 1.1, assume 0-255 range
            pcd = pcd.copy()
            pcd = colors / 255.0
            if not suppress_print:
                print(f"scalePcd.py: scalePcdD({tag}) - {colors.min():.3f}-{colors.max():.3f} -> {pcd.min():.3f}-{pcd.max():.3f}")
        # else:
        #     print(f"scalePcd.py: scalePcdD({tag}) - RGB range: {original_min:.3f} to {original_max:.3f}, already in 0-1 range, no scaling needed")
        
        return pcd
    
    else:
        print(f"scalePcd.py: scalePcdD({tag}) - Unsupported shape {pcd.shape}, expected (N, 6) or (N, 3)")
        return pcd

def scaleSamePcd(pcd1, pcd2, tag=None, suppress_print=True):
    """
    Examine two point clouds and ensure they have the same color scaling.
    The second point cloud will be scaled to match the first one's color range.
    
    Args:
        pcd1: First point cloud array of shape (N, 6) [x, y, z, r, g, b] or RGB array of shape (N, 3) [r, g, b]
        pcd2: Second point cloud array to be scaled
        tag: Optional tag for logging
        suppress_print: Whether to suppress print statements
    
    Returns:
        pcd1, pcd2: Both point clouds with consistent color scaling
    """
    if pcd1 is None or pcd2 is None:
        return pcd1, pcd2
    
    if pcd1.shape[0] == 0 or pcd2.shape[0] == 0:
        return pcd1, pcd2
    
    # Determine the color range of the first point cloud
    if pcd1.shape[1] == 6:  # Full point cloud [x, y, z, r, g, b]
        colors1 = pcd1[:, 3:6]
    elif pcd1.shape[1] == 3:  # RGB only [r, g, b]
        colors1 = pcd1
    else:
        print(f"scalePcd.py: scaleSamePcd({tag}) - Unsupported pcd1 shape {pcd1.shape}, expected (N, 6) or (N, 3)")
        return pcd1, pcd2
    
    # Determine the color range of the second point cloud
    if pcd2.shape[1] == 6:  # Full point cloud [x, y, z, r, g, b]
        colors2 = pcd2[:, 3:6]
    elif pcd2.shape[1] == 3:  # RGB only [r, g, b]
        colors2 = pcd2
    else:
        print(f"scalePcd.py: scaleSamePcd({tag}) - Unsupported pcd2 shape {pcd2.shape}, expected (N, 6) or (N, 3)")
        return pcd1, pcd2
    
    # Check if pcd1 colors are in 0-1 or 0-255 range
    pcd1_max = colors1.max()
    pcd1_in_0_1_range = pcd1_max <= 1.1
    
    # Check if pcd2 colors are in 0-1 or 0-255 range
    pcd2_max = colors2.max()
    pcd2_in_0_1_range = pcd2_max <= 1.1
    
    # Scale pcd2 to match pcd1's range
    if pcd1_in_0_1_range != pcd2_in_0_1_range:
        pcd2 = pcd2.copy()
        if pcd1_in_0_1_range and not pcd2_in_0_1_range:
            # pcd1 is 0-1, pcd2 is 0-255, scale pcd2 to 0-1
            if pcd2.shape[1] == 6:
                pcd2[:, 3:6] = colors2 / 255.0
            else:
                pcd2 = colors2 / 255.0
            if not suppress_print:
                print(f"scalePcd.py: scaleSamePcd({tag}) - Scaled pcd2 from 0-255 to 0-1 range to match pcd1")
        elif not pcd1_in_0_1_range and pcd2_in_0_1_range:
            # pcd1 is 0-255, pcd2 is 0-1, scale pcd2 to 0-255
            if pcd2.shape[1] == 6:
                pcd2[:, 3:6] = colors2 * 255.0
            else:
                pcd2 = colors2 * 255.0
            if not suppress_print:
                print(f"scalePcd.py: scaleSamePcd({tag}) - Scaled pcd2 from 0-1 to 0-255 range to match pcd1")
    else:
        if not suppress_print:
            print(f"scalePcd.py: scaleSamePcd({tag}) - Both point clouds already have the same color scaling")
    
    return pcd1, pcd2